package com.admin.service.impl;

import com.admin.common.context.SampleContext;
import com.admin.common.enums.*;
import com.admin.common.enums.sample.SampleTypeEnum;
import com.admin.common.exception.BizException;
import com.admin.common.shiro.ShiroUtils;
import com.admin.common.thread.ThreadPoolManager;
import com.admin.common.util.DateUtils;
import com.admin.component.sample.SampleHandlerDispatcher;
import com.admin.domain.AdminDO;
import com.admin.domain.Declare;
import com.admin.domain.DeclareSampleRecord;
import com.admin.domain.DeclareScore;
import com.admin.mapper.*;
import com.admin.req.declare.FlagReq;
import com.admin.req.declarereturn.ReturnReq;
import com.admin.req.score.ScoreReq;
import com.admin.service.*;
import com.admin.vo.PageVO;
import com.admin.vo.ResultVO;
import com.admin.vo.declare.*;
import com.admin.vo.declare.province.ProvinceFlagVO;
import com.admin.vo.declareDetail.DeclareDetailVO;
import com.admin.vo.sample.SampleResponse;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * @author yangzhongliang
 * @date 2022/05/16
 */
@Slf4j
@Service
public class DeclareProvinceServiceImpl implements DeclareProvinceService {
    @Autowired
    private DeclareMapper declareMapper;
    @Autowired
    private AdminMapper adminMapper;
    @Autowired
    private DeclareService declareService;
    @Autowired
    private SysParamService sysParamService;
    @Autowired
    private DeclareScoreService declareScoreService;
    @Autowired
    private DeclareLogService declareLogService;
    @Autowired
    private DeclareReturnService declareReturnService;
    @Autowired
    private AdminService adminService;
    @Autowired
    private SampleRecordService sampleRecordService;
    @Autowired
    private SampleHandlerDispatcher sampleHandlerDispatcher;
    @Autowired
    private MenuService menuService;
    @Autowired
    private DeclareScoreMapper declareScoreMapper;

    @Override
    public String getPermissionsColumnsScore() {
        List<String> moduleList = menuService.getPermissionsModule(ShiroUtils.getUserId());
        log.info("totalPermissionsModuleScore 登录用户:{}, 评分权限列表：{}", ShiroUtils.getUserId(), moduleList);
        if (CollectionUtils.isEmpty(moduleList)) {
            return "";
        }
        StringJoiner responseJoiner = new StringJoiner("+");
        for (String s : moduleList) {
            String table =  ProvinceModuleScoreEnum.getText(s);
            if (StringUtils.isEmpty(table)) {
                continue;
            }
            responseJoiner.add(table);
        }
        return responseJoiner.toString();
    }

    @Override
    public Double totalPermissionsModuleScore(Integer declareId, String columnsScore) {
        if (StringUtils.isEmpty(columnsScore)) {
            return 0D;
        }
        Map<String,Object> params = new HashMap<>();
        params.put("columnNames", columnsScore);
        params.put("declareId", declareId);
        log.info("totalPermissionsModuleScore 登录用户:{}, 查询评分参数：{}", ShiroUtils.getUserId(), params);
        Double resultScore = declareScoreMapper.sumScoreByMap(params);
        return resultScore == null ? 0D: resultScore;
    }

    /**
     * 查询 自己 申报的记录
     * @param pageIndex
     * @param pageSize
     * @param params
     * @return
     */
    @Override
    public ResultVO<PageVO<DeclareListVO>> getPageList(Integer pageIndex, Integer pageSize, Map<String, Object> params) {
        ResultVO<PageVO<DeclareListVO>> result = new ResultVO<>();
        PageVO<DeclareListVO> page = new PageVO<>(pageIndex, pageSize);
        List<DeclareListVO> declareListVOList = new ArrayList<>();
        // 查询总数
        String columnsScore = getPermissionsColumnsScore();
        // 区县 用户 - 查询自己区县内的所有申报 记录
        Integer provinceIds = adminService.getResponsibleAreaIds(ShiroUtils.getUserId());
        params.put("provinceIds", Arrays.asList(provinceIds));
        params.put("isSubmitProvince", 1);
        Integer totalCount = declareMapper.countByMap(params);
        page.setTotalCount(totalCount);
        if (totalCount > 0) {
            // 查询管理员信息
            params.put("startIndex", page.getStartIndex());
            params.put("pageSize", page.getPageSize());
            params.put("columnNames", columnsScore);
            List<ProvinceDeclareVO> declareList = declareMapper.selectProvinceDeclares(params);
            if (!CollectionUtils.isEmpty(declareList)) {
                for (ProvinceDeclareVO declare : declareList) {
                    DeclareListVO itemVO = new DeclareListVO();
                    BeanUtils.copyProperties(declare, itemVO);
//                    itemVO.setProvinceScore(totalPermissionsModuleScore(declare.getId(), columnsScore));
                    itemVO.setProvinceScore(declare.getSelfProvinceScore());
                    itemVO.setDeclareStatusStr(DeclareStatusEnum.getText(declare.getDeclareStatus()));
                    itemVO.setDeclareTypeStr(DeclareTypeEnum.getText(declare.getDeclareType()));
                    itemVO.setCreateTimeStr(DateUtils.format(declare.getCreateTime(), DateUtils.DATE_PATTERN_TIME));
                    declareListVOList.add(itemVO);
                }
            }
        }
        page.setData(declareListVOList);
        //申报用户数量 和 实际上报数量
        Map<String,Object> resultMap = new HashMap<>();
        resultMap.put("totalUserQuantity", adminService.totalUserQuantity(MemberLevelEnum.PROVINCE.getKey(), provinceIds));
        resultMap.put("submitUserQuantity", adminService.currentRoundDeclareQuantity(MemberLevelEnum.PROVINCE.getKey(), provinceIds));
        page.setMap(resultMap);
        result.setData(page);
        result.setCode(EnumResult.SUCCESS.getCode());
        result.setMsg(EnumResult.SUCCESS.getMsg());
        return result;
    }


    @Override
    public ResultVO saveScore(Integer userId, ScoreReq scoreReq) {
        //查询当前登录用户所属社区
        AdminDO adminDO = adminMapper.selectByPrimaryKey(userId);
        if (Objects.isNull(adminDO)) {
            throw new BizException(-1, "登录信息已失效,请重新登录!");
        }
        return declareScoreService.save(userId, scoreReq, MemberLevelEnum.PROVINCE.getKey());
    }

    @Override
    public ResultVO provinceReturn(Integer userId, ReturnReq req) {
        return declareReturnService.save(userId, req, MemberLevelEnum.PROVINCE.getKey());
    }



    /**
     * 详情  -  如果退回  有退回原因
     * @param id
     * @return
     */
    @Override
    public DeclareDetailVO detail(Integer id) {
        Declare declare = declareMapper.selectByPrimaryKey(id);
        if (Objects.isNull(declare)) {
            throw new BizException(-1, "申报记录不存在或已删除!");
        }

        //通用详情方法 -
        //新增别的数据
        DeclareDetailVO declareDetailVO = declareService.detail(id, MemberLevelEnum.PROVINCE.getKey());


        return declareDetailVO;
    }


    /**
     * 省级 - 去抽样 - 弹框信息
     *
     * @param userId  用户id
     * @param declareType 申报类型
     * @return
     */
    @Override
    public DeclareSampleVO toSample(Integer userId, Integer declareType) {
        // 如果已抽过 - 校验
        //可能需要根据时间段区间查询,
        DeclareTime declareTime = sysParamService.getDeclareTime();
        if (sampleRecordService.isSampled(userId, declareTime.getStartTime(), declareTime.getEndTime(), declareType)) {
            throw new BizException(-1, "省级已经抽过样了！");
        }
        HashMap params = new HashMap();
        params.put("startTime", DateUtils.dateFormatStr(declareTime.getStartTime()));
        params.put("endTime", DateUtils.dateFormatStr(declareTime.getEndTime()));
        params.put("declareType", declareType);
        params.put("isSubmitProvince", 1);
        params.put("scoreStatus", DeclareScoreStatusEnum.PROVINCE_WAIT.getKey());
        Integer quantity =  declareMapper.countByMap(params);
        if (quantity == null || quantity == 0) {
            throw new BizException(-1, "暂无需要抽样的申报记录!");
        }
        DeclareSampleVO sampleVO = new DeclareSampleVO();
        sampleVO.setQuantity(quantity);
        //涉及市区
        sampleVO.setCityQuantity(declareMapper.countCityNum(params));
        sampleVO.setAreaQuantity(declareMapper.countAreaNum(params));
        return sampleVO;
    }


    @Override
    public DeclareSampleVO saveSample(Integer userId, Integer declareType, Integer sampleRate, Integer sampleScope) {
        // 根据时间 -范围 - 抽样
        AdminDO adminDO = adminMapper.selectByPrimaryKey(userId);
        if (Objects.isNull(adminDO)) {
            throw new BizException(-1, EnumResult.USER_NOT_EXIST.getMsg());
        }
        DeclareTime declareTime = sysParamService.getDeclareTime();
        // 如果已抽过 - 校验 TODO
        if (sampleRecordService.isSampled(userId, declareTime.getStartTime(), declareTime.getEndTime(), declareType)) {
            throw new BizException(-1, "省级已经抽过样了！");
        }

        SampleContext sampleContext = SampleContext
                .builder()
                .startTime(declareTime.getStartTime()).endTime(declareTime.getEndTime())
                .sampleRate(sampleRate).sampleType(sampleScope)
                .declareType(declareType)
                .provinceIdList(Arrays.asList(new String[]{adminDO.getBusinessAreaIds()}))
                .build();

        SampleResponse sampleResponse = sampleHandlerDispatcher.getHandler(SampleTypeEnum.getEnum(sampleScope).name()).sample(sampleContext);

        //封装抽样结果
        DeclareSampleRecord sampleRecord = new DeclareSampleRecord();
        sampleRecord.setDeclareStartTime(declareTime.getStartTime());
        sampleRecord.setDeclareEndTime(declareTime.getEndTime());
        sampleRecord.setSampleType(declareType);
        sampleRecord.setSampleRate(sampleRate.toString());
        sampleRecord.setSampleScope(sampleScope.toString());
        sampleRecord.setSampleNum(sampleResponse.getSampleQuantity());

        JSONObject sampleResult = new JSONObject();
        sampleResult.put("sampledNum", sampleResponse.getSampleQuantity());
        sampleResult.put("cityNum", sampleResponse.getCityQuantity());
        sampleResult.put("areaNum", sampleResponse.getAreaQuantity());
        sampleResult.put("countryNum", sampleResponse.getCountryQuantity());
        sampleResult.put("declareIds", sampleResponse.getIdList());

        sampleRecord.setSampleResult(sampleResult.toString());
        sampleRecord.setRegionIds(adminDO.getResponsibleAreaIds());
        sampleRecord.setRegionNames(adminDO.getResponsibleArea());
        sampleRecord.setSampleLevel(MemberLevelEnum.PROVINCE.getKey());
        sampleRecord.setCreateId(adminDO.getUserId());
        // 保存抽样记录 结果
        sampleRecordService.saveProvinceSample(userId, sampleResponse.getIdList(), sampleRecord);

        DeclareSampleVO declareSampleVO = new DeclareSampleVO();
        declareSampleVO.setDeclareIdList(sampleResponse.getIdList());
        declareSampleVO.setDeclareType(declareType);
        declareSampleVO.setQuantity(sampleResponse.getSampleQuantity());
        declareSampleVO.setCityQuantity(sampleResponse.getCityQuantity());
        declareSampleVO.setAreaQuantity(sampleResponse.getAreaQuantity());
        declareSampleVO.setCountryQuantity(sampleResponse.getCountryQuantity());
        return declareSampleVO;
    }


    /**
     * 省级 - 批量赋分
     * @param userId
     * @param declareIds
     * @return
     */
    @Override
    public Integer batchScore(Integer userId, String declareIds) {
        AdminDO adminDO = adminMapper.selectByPrimaryKey(userId);
        if (Objects.isNull(adminDO)) {
            throw new BizException(-1, "用户信息已失效,请重新登录!");
        }
        Map<String,Object> params = buildBatchScorePrams(userId);
        List<Declare> declareList = declareMapper.selectByMap(params);
        if (CollectionUtils.isEmpty(declareList)) {
            throw new BizException(-1, "暂无需要赋分的申报数据!");
        }
        //异步处理
        ThreadPoolManager.get().execute(new Runnable() {
            @Override
            public void run() {
                for (Declare declare : declareList) {
                    declareScoreService.provinceBatchScore(adminDO, declare);
                }
            }
        });
        return declareList.size();
    }

    /**
     * 省级 - 批量赋分- 弹框详情
     * @param userId
     * @return
     */
    @Override
    public DeclareBatchScoreInfoVO getBatchScoreInfo(Integer userId) {
        // 如果已抽过 - 校验 TODO
        DeclareTime declareTime = sysParamService.getDeclareTime();
        if (!sampleRecordService.isSampled(userId, declareTime.getStartTime(), declareTime.getEndTime())) {
            throw new BizException(-1, "省级还没有抽样！");
        }
        DeclareBatchScoreInfoVO sampleVO = new DeclareBatchScoreInfoVO();
        //时间区间 内 - 非样本,未评分的申报 赋分
        Map<String,Object> params = buildBatchScorePrams(userId);
        Integer quantity =  declareMapper.countByMap(params);
        sampleVO.setQuantity(quantity);
        sampleVO.setItems(declareMapper.getGroupCity(params));
        return sampleVO;
    }

    private Map<String,Object> buildBatchScorePrams(Integer userId) {
        AdminDO adminDO = adminMapper.selectByPrimaryKey(userId);


        Map<String,Object> params = new HashMap<>();
        DeclareTime declareTime = sysParamService.getDeclareTime();
        params.put("startTime", DateUtils.dateFormatStr(declareTime.getStartTime()));
        params.put("endTime", DateUtils.dateFormatStr(declareTime.getEndTime()));
        //非省样本 - 自动赋分
        params.put("isProvinceSample", 0);
        params.put("isSubmitProvince", 1);
        params.put("scoreStatus", DeclareScoreStatusEnum.PROVINCE_WAIT.getKey());
        params.put("provinceIds", Arrays.asList(new String[]{adminDO.getBusinessAreaIds()}));
        return params;
    }

    /**
     * 单个标记
     * @param userId
     * @param flagReq
     * @return
     */
    @Transactional
    @Override
    public Boolean flagDeclare(Integer userId, FlagReq flagReq) {
        AdminDO adminDO = adminMapper.selectByPrimaryKey(userId);
        if (Objects.isNull(adminDO)) {
            throw new BizException(-1, EnumResult.USER_NOT_EXIST.getMsg());
        }
        //更新主表
        Declare declare = declareMapper.selectByPrimaryKey(flagReq.getDeclareId());
        if (Objects.isNull(declare)) {
            throw new BizException(-1, EnumResult.DATA_LOSS_OR_ERROR.getMsg());
        }

        if (!declare.getScoreStatus().equals(DeclareScoreStatusEnum.PROVINCE_SUCCESS.getKey())) {
            throw new BizException(-1, "省级暂无评分,不能标记!");
        }

        Declare updateDeclare = new Declare();
        updateDeclare.setId(declare.getId());
        updateDeclare.setDeclareStatus(flagReq.getDeclareStatus());
        declareMapper.updateByPrimaryKeySelective(updateDeclare);
        //记录日志表
        if (flagReq.getDeclareStatus().equals(DeclareStatusEnum.SUCCESS.getKey())) {
            declareLogService.save(adminDO, flagReq.getDeclareId(), DeclareLogTypeEnum.TYPE_90.getKey(), "标记为通过", flagReq.getRemark());
        } else if (flagReq.getDeclareStatus().equals(DeclareStatusEnum.NOT_SUCCESS.getKey())) {
            declareLogService.save(adminDO, flagReq.getDeclareId(), DeclareLogTypeEnum.TYPE_90.getKey(), "标记为不通过", flagReq.getRemark());
        }
        return true;
    }


    @Override
    public ProvinceFlagVO toBatchFlag(FlagReq flagReq) {
        ProvinceFlagVO flagVO = new ProvinceFlagVO();
        Map<String, Object> params = new HashMap<>();
        DeclareTime declareTime = sysParamService.getDeclareTime();
        params.put("startTime", DateUtils.dateFormatStr(declareTime.getStartTime()));
        params.put("endTime", DateUtils.dateFormatStr(declareTime.getEndTime()));
        //查询省已经评分的申报记录
        params.put("scoreStatus", DeclareScoreStatusEnum.PROVINCE_SUCCESS.getKey());
        params.put("declareStatus", flagReq.getFromDeclareStatus());
        params.put("provinceMinScore", flagReq.getMinScore());
        params.put("provinceMaxScore", flagReq.getMaxScore());
        flagVO.setTotalNum(declareMapper.countByMap(params));
        if (flagVO.getTotalNum() == 0) {
            throw new BizException(-1, "暂无需要标记的数据！");
        }
        List<DeclareBatchScoreItemInfoVO> itemInfoVOS = declareMapper.getGroupCity(params);
        flagVO.setItems(itemInfoVOS);
        return flagVO;
    }

    @Override
    public ResultVO saveBatchFlag(FlagReq flagReq) {
        ResultVO resultVO = new ResultVO();
        Map<String,Object> params = new HashMap<>();
        DeclareTime declareTime = sysParamService.getDeclareTime();
        params.put("startTime", DateUtils.dateFormatStr(declareTime.getStartTime()));
        params.put("endTime", DateUtils.dateFormatStr(declareTime.getEndTime()));
        //查询省已经评分的申报记录
        params.put("scoreStatus", DeclareScoreStatusEnum.PROVINCE_SUCCESS.getKey());
        params.put("declareStatus", flagReq.getFromDeclareStatus());
        params.put("provinceMinScore", flagReq.getMinScore());
        params.put("provinceMaxScore", flagReq.getMaxScore());
        List<Declare> declareList = declareMapper.selectByMap(params);
        if (!CollectionUtils.isEmpty(declareList)) {
            //异步处理
            ThreadPoolManager.get().execute(new Runnable() {
                @Override
                public void run() {
                    for (Declare declare : declareList) {
                        try {
                            // 更新省报标识
                            Declare updateD = new Declare();
                            updateD.setId(declare.getId());
                            updateD.setDeclareStatus(flagReq.getDeclareStatus());
                            declareMapper.updateByPrimaryKeySelective(updateD);
                            // 记录日志
                            if (flagReq.getDeclareStatus().equals(DeclareStatusEnum.SUCCESS.getKey())) {
                                declareLogService.save(ShiroUtils.getUser(), flagReq.getDeclareId(), DeclareLogTypeEnum.TYPE_90.getKey(), "标记为通过", flagReq.getRemark());
                            } else if (flagReq.getDeclareStatus().equals(DeclareStatusEnum.NOT_SUCCESS.getKey())) {
                                declareLogService.save(ShiroUtils.getUser(), flagReq.getDeclareId(), DeclareLogTypeEnum.TYPE_90.getKey(), "标记为不通过", flagReq.getRemark());
                            }
                        } catch (Exception e) {
                            log.error("saveBatchFlag error declareId:{}, error:{}", declare.getId(), e);
                        }
                    }
                }
            });
        }
        resultVO.setCode(0);
        resultVO.setMsg("成功");
        return resultVO;
    }
}
